# coding=utf-8

import sys
import codecs
import pickle
import logging
import traceback
import json
sys.path.append('matchutils')
import matchapi
import python_library.utils as utils
from bind_common import MySQLConn
from bind_common import BindConfig
from bind_common import BindCommon
from bind_common import ErrCode
reload(sys)
sys.setdefaultencoding("utf-8")


class ManageAlbumLoad(object):
  """管理加载到内存中的album
  """

  def __init__(self):
    self._load_synonymy_names()
    self._load_album_from_database()
    #pickle.dump(self.album_set, open("config/album_set", "w"))
    #pickle.dump(self.album_keyword_set, open("config/album_keyword_set", "w"))
    # self.album_set = pickle.load(open("config/album_set", "r"))
    # self.album_keyword_set = pickle.load(open("config/album_keyword_set", "r"))
    logging.info("load album finish")

  def _load_synonymy_names(self):
    """加载同义词字典
    """
    self.synonymy_names = {}
    self.synonymy_reverse = {}
    file = codecs.open("config/syn_words.txt", "r", "utf-8")
    s = file.readlines()
    for line in s:
      if not line:
        continue
      origin_alias_name = line.split("\t")
      if not self.synonymy_names.has_key(origin_alias_name[0]):
        self.synonymy_names[origin_alias_name[0]] = [origin_alias_name[1]]
      else:
        self.synonymy_names[origin_alias_name[0]].append(origin_alias_name[1])
      if not self.synonymy_reverse.has_key(origin_alias_name[1]):
        self.synonymy_reverse[origin_alias_name[1]] = [origin_alias_name[0]]
      else:
        self.synonymy_reverse[origin_alias_name[1]].append(origin_alias_name[0])

  def _load_nets_album(self, conn):
    """加载包含source='nets','bestv'等不参与专辑绑定的站源的album id

    Args:
      conn: 数据库连接
    """
    sql = u"SELECT album_id FROM video WHERE source IN ('nets','bestv') AND album_id IS NOT NULL;"
    data = utils.run_sql(conn, sql)
    if data:
      self._nets_album_set = set([item[0] for item in data])
    else:
      self._nets_album_set = set([])

  def _cut_words_and_save(self, name, video_type, album_id, album):
    """将传入album名称分词并存入内存

    Args:
      name: album名称
      video_type: album类型。电影，电视剧，综艺等
      album_id: album id
      album: album信息字典
    """
    name_words = BindCommon.sentence_segment(name)
    if name_words:
      for name_word in name_words:
        if name_word:
          self.album_set.setdefault(video_type, {}).setdefault(name_word, {})[album_id] = album
          self.album_keyword_set.setdefault(album_id, []).append(name_word)

  def _handle_album_load_old(self, album):
    """旧算法分桶逻辑：将传入album存入内存

    Args:
      album: album信息字典
    """
    video_type = album.pop("video_type")
    album_id = album["id"]
    if not album_id or album_id in self._nets_album_set:
      return
    album = BindCommon.massage(album)
    name = album["name"][0]
    if name:
      self.album_set.setdefault(video_type, {}).setdefault(name, {})[album_id] = album
      self.album_keyword_set.setdefault(album_id, []).append(name)
      self._cut_words_and_save(name, video_type, album_id, album)
    if self.synonymy_names.has_key(name):
      sysnonymy_name = self.synonymy_names[name]
      for name_s in sysnonymy_name:
        self.album_set.setdefault(video_type, {}).setdefault(name_s, {})[album_id] = album
        self.album_keyword_set.setdefault(album_id, []).append(name_s)
        self._cut_words_and_save(name_s, video_type, album_id, album)
    if self.synonymy_reverse.has_key(name):
      sysnonymy_name = self.synonymy_reverse[name]
      for name_s in sysnonymy_name:
        self.album_set.setdefault(video_type, {}).setdefault(name_s, {})[album_id] = album
        self.album_keyword_set.setdefault(album_id, []).append(name_s)
        self._cut_words_and_save(name_s, video_type, album_id, album)
    actor_list = album.get("actor_name", None)
    if actor_list:
      self.album_keyword_set.setdefault(album_id, []).extend(actor_list)
      for actor in actor_list:
        self.album_set.setdefault(video_type, {}).setdefault(actor, {})[album_id] = album
    director_list = album.get("director_name", None)
    if director_list:
      self.album_keyword_set.setdefault(album_id, []).extend(director_list)
      for director in director_list:
        self.album_set.setdefault(video_type, {}).setdefault(director, {})[album_id] = album

  def _handle_album_load_new(self, album):
    """新算法分桶逻辑：将传入album存入内存

    Args:
      album: album信息字典
    """
    video_type = album.pop("video_type")
    album_id = album["id"]
    if not album_id or album_id in self._nets_album_set:
      return
    album = BindCommon.massage(album)
    album_item = BindCommon.translate_for_new(album, video_type)
    keyword_list = matchapi.get_keywords(album_item)
    if keyword_list:
      self.album_keyword_set.setdefault(album_id, []).extend(keyword_list)
      for keyword in keyword_list:
        self.album_set.setdefault(video_type, {}).setdefault(keyword, {})[album_id] = album

  def _load_album_from_database(self):
    """从数据库中加载album信息
    """
    with MySQLConn(BindConfig.DB) as db:
      self.album_set = {}
      self.album_keyword_set = {}
      conn = db.get()
      self._load_nets_album(conn)
      query_names = BindConfig.ALBUM_FIELDS.replace(BindConfig.NAME_FIELDS,
                                               "CONCAT_WS(';', %s) as name" % BindConfig.NAME_FIELDS)
      query_names = query_names + BindConfig.NAME_SQL_FOR_NEW_ALG
      sql_format = "SELECT %s FROM album WHERE state = 1 and id > %%s and (content_type=1 or content_type is null) order by id LIMIT 10000" % query_names
      logging.info("sql_format:%s" % sql_format)
      last_id = 0
      while 1:
        sql = sql_format % last_id
        logging.info("Loading start id:%s" % str(last_id))
        query_fields = BindConfig.ALBUM_FIELDS.replace(BindConfig.NAME_FIELDS, "name")
        query_fields = query_fields + BindConfig.NAME_FOR_NEW_ALG
        data = utils.run_sql(conn, sql, fields=query_fields.split(","))
        if not data:
          break
        last_id = data[-1]["id"]
        for album in data:
          self._handle_album_load_new(album)

  def _add_album(self, album_id):
    """添加album

    Args:
      album_id: album id

    Returns:
      True--添加成功, False--添加失败
    """
    query_names = BindConfig.ALBUM_FIELDS.replace(BindConfig.NAME_FIELDS,
                                             "CONCAT_WS(';', %s) as name" % BindConfig.NAME_FIELDS)
    query_names = query_names + BindConfig.NAME_SQL_FOR_NEW_ALG
    sql = "SELECT %s FROM album WHERE (content_type=1 OR content_type IS NULL) AND id=%s" % (query_names, album_id)
    query_fields = BindConfig.ALBUM_FIELDS.replace(BindConfig.NAME_FIELDS, "name")
    query_fields = query_fields + BindConfig.NAME_FOR_NEW_ALG
    data = utils.run_sql(self._conn, sql, fields=query_fields.split(","))
    if not data:
      logging.info("Failed to get album, album_id:[%s]" % album_id)
      return False
    album = data[0]
    # self._handle_album_load_old(album)
    self._handle_album_load_new(album)
    return True

  def add_album_list(self, album_id_str):
    """添加album

    Args:
      album_id_str: album id；或为album id列表，以,分割

    Returns:
      返回的信息,可能包含的信息有两个：
        error: ErrCode信息，标志本次请求返回值的类型
        ret: 本次请求具体的返回信息。返回固定值None
    """
    try:
      if not album_id_str:
        return ErrCode.WRONG_PARAM, None
      try:
        album_id_list = album_id_str.split(",")
      except:
        return ErrCode.WRONG_PARAM, None
      with MySQLConn(BindConfig.DB) as db:
        self._conn = db.get()
        for album_id in album_id_list:
          if not self._add_album(int(album_id)):
            return ErrCode.INVALID_ALBUMID, None
        return ErrCode.OK, None
    except:
      logging.exception("Failed to add album, album_id:[%s]" % album_id_str)
      traceback.print_exc()
      return ErrCode.EXCEPT, None

  def del_album(self, album_id, video_type):
    """删除album

    Args:
      album_id: album id
      video_type: album类型。电影，电视剧，综艺等

    Returns:
      返回的信息,可能包含的信息有两个：
        error: ErrCode信息，标志本次请求返回值的类型
        ret: 本次请求具体的返回信息。返回固定值None
    """
    try:
      if not album_id or not video_type:
        return ErrCode.WRONG_PARAM, None
      album_id = int(album_id)
      video_type = int(video_type)
      keyword_list = self.album_keyword_set.pop(album_id, None)
      if not keyword_list:
        logging.info("none keyword when delete album, album_id:[%s]" % album_id)
        return ErrCode.INVALID_ALBUMID, None
      for keyword in keyword_list:
        self.album_set.get(video_type, {}).get(keyword, {}).pop(album_id, None)
      logging.info("Success to delete album, album_id:[%s]" % album_id)
      return ErrCode.OK, None
    except:
      logging.exception("Failed to delete album, album_id:[%s]" % album_id)
      traceback.print_exc()
      return ErrCode.EXCEPT, None

  def get_album_in_memary(self, album_id, video_type):
    """得到内存中的album信息（用于debug）

    Args:
      album_id: album id
      video_type: album类型。电影，电视剧，综艺等

    Returns:
      内存中对应id的album信息
    """
    if not album_id or not video_type:
      return {}
    key_word_list = self.album_keyword_set.get(int(album_id))
    result = {"key_word_list": key_word_list}
    if key_word_list:
      result["album"] = self.album_set.get(int(video_type), {}).get(key_word_list[0], {})
    return json.dumps(result, encoding=BindConfig.ENCODING, ensure_ascii=False)